package com.bhajanswarupa.paginationutils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

public class PageImpl<T> implements Page<T>, Serializable {

	protected List<T> results;

	protected int pageSize;

	protected int pageNumber;

	protected int totalResults;

    private static final Logger LOGGER = LoggerFactory.getLogger(PageImpl.class);
	private static final long serialVersionUID = 2893637685294726369L;


	/**
	 * 
	 */
	protected PageImpl() {

		this.pageNumber = 0;
		this.pageSize = 0;
		this.results = new ArrayList<T>();
		this.totalResults = 0;
	}


	/**
	 * @param page
	 */
	public PageImpl(Page<T> page) {

		this.pageSize = page.getPageSize();
		this.pageNumber = page.getPageNumber();
		this.totalResults = page.getTotalNumberOfElements();
		this.results = new ArrayList<T>();
		results.addAll(page.getThisPageElements());
	}


	/**
	 * @param pageSize
	 * @param pageNumber
	 * @param totalResults
	 * @param list
	 */
	public PageImpl(int pageSize, int pageNumber, int totalResults, List<T> list) {

		this.pageSize = pageSize;
		this.pageNumber = pageNumber;
		this.totalResults = totalResults;
		this.results = new ArrayList<T>();
		results.addAll(list);
	}


	/**
	 * @see com.bhajanswarupa.paginationutils.Page#isFirstPage()
	 */
	public boolean isFirstPage() {

		return pageNumber == Page.FIRST_PAGE;
	}


	/**
	 * @see com.bhajanswarupa.paginationutils.Page#isLastPage()
	 */
	public boolean isLastPage() {

		return pageNumber >= getLastPageNumber();
	}


	/**
	 * @see com.bhajanswarupa.paginationutils.Page#getHasNextPage()
	 */
	public boolean getHasNextPage() {

		if (pageSize == PAGESIZE_ALLRESULTS) {
			return false;
		} else {
			return results.size() > pageSize;
		}
	}


	/**
	 * @see com.bhajanswarupa.paginationutils.Page#getHasPreviousPage()
	 */
	public boolean getHasPreviousPage() {

		return pageNumber > Page.FIRST_PAGE;
	}


	/**
	 * @see com.bhajanswarupa.paginationutils.Page#getLastPageNumber()
	 */
	public int getLastPageNumber() {

		if (pageSize == PAGESIZE_ALLRESULTS) {
			return -1;
		} else {

			/*
			 * We use the Math.floor() method because page numbers are
			 * zero-based (i.e. the first page is page 0).
			 */
			double totalResults = new Integer(getTotalNumberOfElements())
					.doubleValue();
			return new Double(Math.floor((totalResults - 1) / pageSize))
					.intValue();
		}
	}


	/**
	 * @return
	 */
	public List<T> getThisPageElements() {

		/*
		 * Since we retrieved one more than the specified pageSize when the
		 * class was constructed, we now trim it down to the pageSize if a next
		 * page exists.
		 */
		return getHasNextPage() ? results.subList(0, pageSize) : results;
	}


	/**
	 * @see com.bhajanswarupa.paginationutils.Page#getTotalNumberOfElements()
	 */
	public int getTotalNumberOfElements() {

		return totalResults;
	}


	/**
	 * @see com.bhajanswarupa.paginationutils.Page#getFirstResultNumber()
	 */
	public int getFirstResultNumber() {

		if (pageSize == PAGESIZE_ALLRESULTS) {
			return 1;
		} else {
			return pageNumber * pageSize + 1;
		}
	}


	/**
	 * @see com.bhajanswarupa.paginationutils.Page#getLastResultNumber()
	 */
	public int getLastResultNumber() {

		if (pageSize == PAGESIZE_ALLRESULTS) {
			return getTotalNumberOfElements();
		} else {
			int fullPage = getFirstResultNumber() + pageSize - 1;
			return getTotalNumberOfElements() < fullPage ? getTotalNumberOfElements()
					: fullPage;
		}
	}


	/**
	 * @see com.bhajanswarupa.paginationutils.Page#getNextPageNumber()
	 */
	public int getNextPageNumber() {

		return pageNumber + 1;
	}


	/**
	 * @see com.bhajanswarupa.paginationutils.Page#getPreviousPageNumber()
	 */
	public int getPreviousPageNumber() {

		return pageNumber - 1;
	}


	/**
	 * @see com.bhajanswarupa.paginationutils.Page#getPageSize()
	 */
	public int getPageSize() {

		return pageSize;
	}


	/**
	 * @see com.bhajanswarupa.paginationutils.Page#getPageNumber()
	 */
	public int getPageNumber() {

		return pageNumber;
	}

}
